package com.ccl.keyassistant.utils;
/*
 *项目名     keyassistant
 *包名       com.ccl.keyassistant.utils
 *文件名     EncryptUtil
 *创建者     ccl
 *创建时间   2019-04-09 19:34
 *注解       加解密类
 */

import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Base64;
import android.widget.Switch;

import com.ccl.keyassistant.commons_codec.digest.DigestUtils;
import com.ccl.keyassistant.db.DBDataHelper;
import com.ccl.keyassistant.db.DBHelper;
import com.ccl.keyassistant.entity.BaseModel;
import com.ccl.keyassistant.entity.KeyModel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class EncryptUtil {
    private static final String ENCRYPT_TYPE = "AES";
    private static final int KEY_SIZE = 16;
    private static final int BUFFER_SIZE = 1024 * 2;
    private static String baseString;
    private static final String suffix = ".ka";

    public static byte[] getRandom() {
        byte[] buf = new byte[KEY_SIZE];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(buf);
        baseString = Base64.encodeToString(buf, Base64.DEFAULT);
        return buf;
    }

    public static Key getKey(byte[] bytes) {
        Key secretKeySpec = new SecretKeySpec(bytes, ENCRYPT_TYPE);
        return secretKeySpec;
    }

    public static synchronized void encrypt(Context context, File file) {
        if (file != null && file.exists()) {
            byte[] random = getRandom();
            Key key = getKey(random);
            try {
                //文件输入，输出流

                File out = new File(file.getAbsolutePath() + suffix);
                if(!out.exists()){
                    out.createNewFile();
                }
                FileOutputStream fos = new FileOutputStream(out);
                FileInputStream fis = new FileInputStream(file);
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
                cipher.init(Cipher.ENCRYPT_MODE, key);
                byte[] buffer = new byte[BUFFER_SIZE];
                int len = 0;

                CipherInputStream cipherInputStream = new CipherInputStream(fis, cipher);
                while ((len = cipherInputStream.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                    fos.flush();
                }

                fos.close();
                fis.close();
                cipherInputStream.close();
                Thread.sleep(500);
                //获取加密后文件的hash
                File en_file = new File(file.getAbsolutePath() + suffix);
                FileInputStream fileInputStream = new FileInputStream(en_file);
                String sha1Hex = DigestUtils.sha1Hex(fileInputStream);
                fileInputStream.close();
                KeyModel temp_key = new KeyModel();
                temp_key.file_name = file.getName();
                temp_key.file_hash = sha1Hex;
                temp_key.remark = "local file";
                temp_key.create_time = FileUtil.getTime();
                temp_key.en_type = ENCRYPT_TYPE;
                //TODO 存储密钥
                temp_key.password = baseString;

                //更新数据库
                DBDataHelper helper = DBDataHelper.getInstance(context);
                String whereCaluse = DBHelper.FILEHASH + " = ? and" + DBHelper.EN_TYPE + " = ?";
                int update = helper.update(DBHelper.TABLE_KEY, whereCaluse, new String[]{
                        temp_key.file_hash, temp_key.en_type
                }, temp_key);
                if (update <= 0) {
                    helper.insert(
                            DBHelper.TABLE_KEY, temp_key
                    );
                }
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

    public static boolean decrypt(Context context, File file) {
        if (file != null && file.exists()) {
            try {
                FileInputStream fileInputStream = new FileInputStream(file);

                String sha1Hex = DigestUtils.sha1Hex(fileInputStream);
                //解密，从数据库中查询
                ArrayList<BaseModel> select = DBDataHelper.getInstance(context).
                        select(DBHelper.TABLE_KEY,
                                new String[]{DBHelper.PASSWORD},
                                DBHelper.FILEHASH + " = ? and" + DBHelper.EN_TYPE + " = ?"
                                , new String[]{sha1Hex, ENCRYPT_TYPE}, null, KeyModel.class);

                if (select != null && select.size() > 0) {
                    KeyModel model = (KeyModel) select.get(0);
                    //TODO 取出密钥
                    byte[] key = Base64.decode(model.password, Base64.DEFAULT);
                    //打开文件流
                    FileInputStream fileInStream = new FileInputStream(file);
                    File out = new File(file.getAbsolutePath().replace(suffix, ""));
                    if(!out.exists()){
                        out.createNewFile();
                    }
                    FileOutputStream fileOutStream = new FileOutputStream(out);
                    byte[] buffer = new byte[BUFFER_SIZE];
                    int len = 0;
                    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
                    cipher.init(Cipher.DECRYPT_MODE, getKey(key));
                    CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutStream, cipher);
                    while ((len = fileInStream.read(buffer)) != -1) {
                        cipherOutputStream.write(buffer, 0, len);
                        cipherOutputStream.flush();
                    }

                    fileInStream.close();
                    cipherOutputStream.close();
                    fileOutStream.close();
                    return true;
                }else {
                    return false;
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}
